Terraform で GCP IAM 設定どれ使うのがいいのか
なんかいろいろある
google_project_iam_policy プロジェクト全体の IAM を Terraform で管理する
google_project_iam_binding 特定の role 以下を Terraform で管理する
google_project_iam_member member と role のリレーションを1つずつ管理する、めんどいが管理外の設定と共存できる
Additive と Authorative
additive: add members to role, old members are not deleted from this role.
authoritative: set the role's members (including removing any not listed), unlisted roles are not affected.
Additive: 既にプロジェクトに紐付いてるものは操作しない、tf, tfstate に書いているものは追加 & 削除される
non-authoritative とも書かれてる
Authoritative: 既存のものを置き換える、tf で完全に制御する、対象でない role は影響を受けない
google_project_iam_policy
Authoritative に project の role 全管理するのに使う
binding セクションを複数書ける、複数書いてまとめてバーン
terraform import google_project_iam_policy.my_project your-project-id で import
当然手元の tf に写経しまくらないといけないので plan するとめちゃくちゃ差分が出る
API 有効にしたタイミングで追加されるようなのも
code:policy.diff
...
- {
- members = [
- "serviceAccount:service-51557482590@gcf-admin-robot.iam.gserviceaccount.com",
]
- role = "roles/cloudfunctions.serviceAgent"
},
- {
- members = [
- "serviceAccount:service-51557482590@gcp-sa-cloudscheduler.iam.gserviceaccount.com",
]
- role = "roles/cloudscheduler.serviceAgent"
},
- {
- members = [
- "serviceAccount:service-51557482590@compute-system.iam.gserviceaccount.com",
]
- role = "roles/compute.serviceAgent"
},
- {
- members = [
- "serviceAccount:51557482590-compute@developer.gserviceaccount.com",
- "serviceAccount:51557482590@cloudservices.gserviceaccount.com",
- "serviceAccount:hogehoge@appspot.gserviceaccount.com",
- "serviceAccount:localhost@hogehoge.iam.gserviceaccount.com",
- "serviceAccount:service-51557482590@containerregistry.iam.gserviceaccount.com",
]
- role = "roles/editor"
},
...
google_project_iam_binding
code:binding.tf
resource "google_project_iam_binding" "project" {
project = "your-project-id"
role = "roles/editor"
members = [
"user:jane@example.com",
"serviceAccount:${google_service_account.sa.email}"
]
}
role に対して Authoritative、その role は terraform で管理する
terraform import google_project_iam_binding.my_project "your-project-id roles/viewer"
これが正道な気はするが
role ごとにリソースを作るので管理したいロールが増えるとめんどい
role ごとに import していく面倒さ
role 内の member を増減させても index ズレの差分は出ない
API を有効にしたりした際に role やサービスアカウントが増えると差分が出る
サービスエージェント系は roles/hoge.serviceAgent っていう role になっていそう
ユーザの使うものと分かれていて偉い
Terraform 意外の経路から role のメンバーが増えるのがありえると import する必要があるのはそう
google_project_iam_member
role と member 1:1 でくっつけていく
Additive なのが気楽でよいが resource を作りまくるのはだるい
ループで作ると index ズレが起きる → setprodcut で map して for_each テク(下部の例)
code:member.tf
resource "google_project_iam_member" "project" {
project = "your-project-id"
role = "roles/editor"
member = "user:jane@example.com"
}
例: 複数ユーザに複数の role を与える
たとえば違うチームのメンバーに、プロジェクトレベルで BigQuery の dataViewer と jobUser を与えるとする
google_project_iam_binding を使う
code:bq_binding.tf
variable "bq_additional_users" {
type = set(string)
default = [
"user:foo@example.com"
"user:bar@example.com"
"user:baz@example.com"
]
}
resource "google_project_iam_binding" "bq_additional_users_bigquery_dataViewer" {
role = "roles/bigquery.dataViewer"
members = var.bq_additional_users
}
resource "google_project_iam_binding" "bq_additional_users_bigquery_jobUser" {
role = "roles/bigquery.jobUser"
members = var.bq_additional_users
}
google_project_iam_member を使う
code:bq_member.tf
variable "bq_additional_roles" {
type = set(string)
default = [
"roles/bigquery.dataViewer",
"roles/bigquery.jobUser",
]
}
variable "bq_additional_users" {
type = set(string)
default = [
"user:foo@example.com"
"user:bar@example.com"
"user:baz@example.com"
]
}
locals {
# setproduct で roles と users の組み合わせを作って map にする
role_user = {
for v in setproduct(var.bq_additional_users, var.bq_additional_roles) : "${v0}:${v1}" => { }
}
}
resource "google_project_iam_member" "bq_additional_users" {
for_each = local.role_user
member = each.value.user
role = each.value.role
}